package com.mmall.service.impl;

import com.alipay.api.AlipayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.ExtendParams;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayMonitorServiceImpl;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.alipay.demo.trade.service.impl.AlipayTradeWithHBServiceImpl;
import com.alipay.demo.trade.utils.ZxingUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mmall.common.Const;
import com.mmall.common.ServerResponse;
import com.mmall.dao.*;
import com.mmall.pojo.*;
import com.mmall.service.IOrderService;
import com.mmall.util.BigDecimalUtil;
import com.mmall.util.DateTimeUtil;
import com.mmall.util.FTPUtil;
import com.mmall.util.PropertiesUtil;
import com.mmall.vo.MyAccountVo;
import com.mmall.vo.OrderProductVo;
import net.sf.jsqlparser.schema.Server;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

@Service("iOrderService")
public class OrderServiceImpl implements IOrderService {
    // 支付宝当面付2.0服务
    private static AlipayTradeService   tradeService;
    static {
        /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
         *  Configs会读取classpath下的zfbinfo.properties文件配置信息，如果找不到该文件则确认该文件是否在classpath目录
         */
        Configs.init("zfbinfo.properties");
        /** 使用Configs提供的默认参数
         *  AlipayTradeService可以使用单例或者为静态成员对象，不需要反复new
         */
        tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
    }
    private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private OrderProductMapper orderProductMapper;
    @Autowired
    private PayInfoMapper payInfoMapper;
    @Autowired
    private CartMapper cartMapper;
    @Autowired
    private ProductMapper productMapper;

    public  ServerResponse createOrder(Integer userId,Integer productId,Integer buyNumber){
        BigDecimal payment = BigDecimal.valueOf(buyNumber);
        //生成订单
        OrderProduct orderProduct = this.assembleOrder(userId,productId,payment);
        if(orderProduct == null){
            return ServerResponse.createByErrorMessage("生成订单错误");
        }
        Product product = productMapper.selectByPrimaryKey(orderProduct.getProductId());
        if(product.getRemainStock()<buyNumber){
            return ServerResponse.createByErrorMessage("库存数量不足");
        }
        //生成成功,我们要减少我们产品的库存
        this.reduceProductStock(orderProduct);
        //返回给前端数据
        OrderProductVo orderVo = assembleOrderVo(orderProduct);
        return ServerResponse.createBySuccess(orderVo);
    }

    private OrderProductVo assembleOrderVo(OrderProduct orderProduct){
        OrderProductVo orderVo = new OrderProductVo();
        orderVo.setOrderNo(orderProduct.getOrderNo());
        orderVo.setPayment(orderProduct.getPayment());
        orderVo.setPaymentType(orderProduct.getPaymentType());
        orderVo.setPaymentTypeDesc(Const.PaymentTypeEnum.codeOf(orderProduct.getPaymentType()).getValue());
        orderVo.setStatus(orderProduct.getStatus());
        orderVo.setStatusDesc(Const.OrderStatusEnum.codeOf(orderProduct.getStatus()).getValue());
        orderVo.setProductId(orderProduct.getProductId());
        orderVo.setPaymentTime(DateTimeUtil.dateToStr(orderProduct.getPaymentTime()));
        orderVo.setEndTime(DateTimeUtil.dateToStr(orderProduct.getEndTime()));
        orderVo.setCreateTime(DateTimeUtil.dateToStr(orderProduct.getCreateTime()));
        orderVo.setCloseTime(DateTimeUtil.dateToStr(orderProduct.getCloseTime()));
        return orderVo;
    }
    private void reduceProductStock(OrderProduct orderProduct){
            Product product = productMapper.selectByPrimaryKey(orderProduct.getProductId());
            Integer payment=orderProduct.getPayment().intValue();
            product.setRemainStock(product.getRemainStock()-payment);
            productMapper.updateByPrimaryKeySelective(product);
    }

    private OrderProduct assembleOrder(Integer userId,Integer productId,BigDecimal payment){
        OrderProduct orderProduct = new OrderProduct();
        long orderNo = this.generateOrderNo();
        orderProduct.setOrderNo(orderNo);
        orderProduct.setStatus(Const.OrderStatusEnum.NO_PAY.getCode());
        orderProduct.setPaymentType(Const.PaymentTypeEnum.ONLINE_PAY.getCode());
        orderProduct.setPayment(payment);

        orderProduct.setUserId(userId);
        orderProduct.setProductId(productId);
        //发货时间等等
        //付款时间等等
        int rowCount = orderProductMapper.insert(orderProduct);
        if(rowCount > 0){
            return orderProduct;
        }
        return null;
    }

    private long generateOrderNo(){
        long currentTime =System.currentTimeMillis();
        return currentTime+new Random().nextInt(100);
    }


    public ServerResponse pay(Long orderNo, Integer userId, String path) {
        Map<String, String> resultMap = Maps.newHashMap();
        OrderProduct orderProduct = orderProductMapper.selectByUserIdAndOrderNo(userId, orderNo);
        if (orderProduct == null) {
            return ServerResponse.createByErrorMessage("用户没有该订单");
        }
        resultMap.put("orderNo", String.valueOf(orderProduct.getOrderNo()));
        // (必填) 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，
        // 需保证商户系统端不能重复，建议通过数据库sequence生成，
        String outTradeNo = orderProduct.getOrderNo().toString();

        // (必填) 订单标题，粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
        String subject = new StringBuilder().append("happymall扫码支付，订单号：").append(outTradeNo).toString();

        // (必填) 订单总金额，单位为元，不能超过1亿元
        // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
        String totalAmount = orderProduct.getPayment().toString();

        // (可选) 订单不可打折金额，可以配合商家平台配置折扣活动，如果酒水不参与打折，则将对应金额填写至此字段
        // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
        String undiscountableAmount = "0";

        // 卖家支付宝账号ID，用于支持一个签约账号下支持打款到不同的收款账号，(打款到sellerId对应的支付宝账号)
        // 如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
        String sellerId = "";

        // 订单描述，可以对交易或商品进行一个详细地描述，比如填写"购买商品2件共15.00元"
        String body = new StringBuilder().append("订单").append(outTradeNo).append("购买商品共").append(totalAmount).append("元").toString();

        // 商户操作员编号，添加此参数可以为商户操作员做销售统计
        String operatorId = "test_operator_id";

        // (必填) 商户门店编号，通过门店号和商家后台可以配置精准到门店的折扣信息，详询支付宝技术支持
        String storeId = "test_store_id";

        // 业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId("2088100200300400500");
        // 支付超时，定义为120分钟
        String timeoutExpress = "120m";
        // 商品明细列表，需填写购买商品详细信息，
        List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();
        List<OrderProduct> orderProductList = orderProductMapper.getByOrderNoUserId(orderNo, userId);
        long price=1;
        for (OrderProduct orderProduct1 : orderProductList) {
            String productName=productMapper.selectByPrimaryKey(orderProduct1.getProductId()).getName();
            GoodsDetail goods = GoodsDetail.newInstance(String.valueOf(orderProduct1.getProductId()), productName, price, orderProduct1.getPayment().intValue());
            goodsDetailList.add(goods);
        }
        // 创建扫码支付请求builder，设置请求参数
        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
                .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
                .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
                .setTimeoutExpress(timeoutExpress)
                .setNotifyUrl(PropertiesUtil.getProperty("alipay.callback.url"))//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
                .setGoodsDetailList(goodsDetailList);
        /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
         *  Configs会读取classpath下的zfbinfo.properties文件配置信息，如果找不到该文件则确认该文件是否在classpath目录
         */
        Configs.init("zfbinfo.properties");
        /** 使用Configs提供的默认参数
         *  AlipayTradeService可以使用单例或者为静态成员对象，不需要反复new
         */
        AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                logger.info("支付宝预下单成功: )");

                AlipayTradePrecreateResponse response = result.getResponse();
                dumpResponse(response);
                String qrPathWeb="D:\\qrCode";
                File folder = new File(qrPathWeb);
                if (!folder.exists()) {
                    folder.setWritable(true);
                    folder.mkdirs();
                }
                // 需要修改为运行机器上的路径
                String qrPath = String.format(qrPathWeb + File.separator + "qr-%s.png",
                        response.getOutTradeNo());
                String qrFileName = String.format("qr-%s.png", response.getOutTradeNo());
                ZxingUtils.getQRCodeImge(response.getQrCode(), 256, qrPath);
//                File targetFile = new File(path, qrFileName);
//                try {
//                    FTPUtil.uploadFile(Lists.newArrayList(targetFile));
//                } catch (IOException e) {
//                    logger.error("上传二维码异常", e);
//                    e.printStackTrace();
//                }
//                logger.info("qrPath:" + qrPath);
                String qrUrl = PropertiesUtil.getProperty("ftp.server.http.prefix") + qrFileName;
                resultMap.put("qrUrl", qrUrl);
                return ServerResponse.createBySuccess(resultMap);
            case FAILED:
                logger.error("支付宝预下单失败!!!");
                return ServerResponse.createByErrorMessage("支付宝预下单失败!!!");
            case UNKNOWN:
                logger.error("系统异常，预下单状态未知!!!");
                return ServerResponse.createByErrorMessage("系统异常，预下单状态未知!!!");
            default:
                logger.error("不支持的交易状态，交易返回异常!!!");
                return ServerResponse.createByErrorMessage("不支持的交易状态，交易返回异常!!!");
        }
    }
    private void dumpResponse(AlipayResponse response) {
        if (response != null) {
            logger.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
            if (StringUtils.isNotEmpty(response.getSubCode())) {
                logger.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
                        response.getSubMsg()));
            }
            logger.info("body:" + response.getBody());
        }
    }
    public ServerResponse aliCallback(Map<String,String> params){
        Long orderNo = Long.parseLong(params.get("out_trade_no"));
        String tradeNo = params.get("trade_no");
        String tradeStatus = params.get("trade_status");
        OrderProduct orderProduct = orderProductMapper.selectByOrderNo(orderNo);
        if(orderProduct == null){
            return ServerResponse.createByErrorMessage("非现在金服的订单,回调忽略");
        }
        if(orderProduct.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){
            return ServerResponse.createBySuccess("支付宝重复调用");
        }
        if(Const.AlipayCallback.TRADE_STATUS_TRADE_SUCCESS.equals(tradeStatus)){
            orderProduct.setPaymentTime(DateTimeUtil.strToDate(params.get("gmt_payment"),"yyyy-MM-dd HH:mm:ss"));
            orderProduct.setStatus(Const.OrderStatusEnum.PAID.getCode());
            orderProductMapper.updateByPrimaryKeySelective(orderProduct);
        }
        PayInfo payInfo = new PayInfo();
        payInfo.setUserId(orderProduct.getUserId());
        payInfo.setOrderNo(orderProduct.getOrderNo());
        payInfo.setPayPlatform(Const.PayPlatformEnum.ALIPAY.getCode());
        payInfo.setPlatformNumber(tradeNo);
        payInfo.setPlatformStatus(tradeStatus);
        payInfoMapper.insert(payInfo);
        return ServerResponse.createBySuccess();
    }

    public ServerResponse getProductName(Long orderNo){
        Integer productId=orderProductMapper.selectByOrderNo(orderNo).getProductId();
        String productName=productMapper.selectByPrimaryKey(productId).getName();
        if(productName!=null){
            return ServerResponse.createBySuccess(productName);
        }
        return ServerResponse.createBySuccessMessage("查询商品名称失败");
    }

    public ServerResponse queryOrderPayStatus(Integer userId,Long orderNo){
        OrderProduct orderProduct = orderProductMapper.selectByUserIdAndOrderNo(userId,orderNo);
        if(orderProduct == null){
            return ServerResponse.createByErrorMessage("用户没有该订单");
        }
        if(orderProduct.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){
            return ServerResponse.createBySuccess();
        }
        return ServerResponse.createByError();
    }

    public ServerResponse getmyAccount(Integer userId){
        List<Map> orderProductMap = orderProductMapper.getmyAccountUserId(userId);
        if(orderProductMap == null){
            return ServerResponse.createByErrorMessage("用户没有购买产品");
        }
        MyAccountVo myAccountVo=new MyAccountVo();
        List<String> myProductNameList=myAccountVo.getMyProductName();
        List<Integer> myProductPriceList=myAccountVo.getMyProductPrice();
        Integer sumPrice=0;
        for(Map map:orderProductMap) {
            Integer productId = Integer.valueOf(map.get("product_id").toString());
            Integer productPrice = Integer.valueOf(map.get("sumpayment").toString());
            Product product=productMapper.selectByPrimaryKey(productId);
            String productName=product.getName();
            myProductNameList.add(productName);
            myProductPriceList.add(productPrice);
            sumPrice+=productPrice;
        }
        myAccountVo.setMyAccount(sumPrice);
        return ServerResponse.createBySuccess(myAccountVo);
    }
}
